package pers.lonestar.framework.utils.support.analysis.handler;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.Attributes;

import net.sf.cglib.beans.BeanMap;
import pers.lonestar.framework.utils.support.contexts.XlsxReadContext;
import pers.lonestar.framework.utils.support.converters.Converter;
import pers.lonestar.framework.utils.support.converters.DefaultConverter;
import pers.lonestar.framework.utils.support.exception.ExcelConvertException;
import pers.lonestar.framework.utils.support.metadata.CellData;
import pers.lonestar.framework.utils.support.metadata.read.ReadSheet;
import pers.lonestar.framework.utils.support.utils.ConverterUtil;
import pers.lonestar.framework.utils.support.utils.FieldUtil;
import pers.lonestar.framework.utils.support.utils.PositionUtil;

public class RowTagHandler extends AbstractXlsxTagHandler {
    @Override
    public void startElement(XlsxReadContext xlsxReadContext, ReadSheet readSheet, String name, Attributes attributes) {
        readSheet.setCellDataMap(new HashMap<>());
        readSheet.setRowIndex(PositionUtil.getRowByRowTagt(attributes.getValue("r"), readSheet.getRowIndex()));
    }

    @Override
    public void endElement(XlsxReadContext xlsxReadContext, ReadSheet readSheet, String name) {
        if (readSheet.getRowIndex() >= readSheet.getHeadNum()) {
            Object resultObj = cellDataMapToObject(readSheet);
            xlsxReadContext.getFluxSink().next(resultObj);
        }
    }

    private Object cellDataMapToObject(ReadSheet readSheet) {
        Object resultObject = null;
        Map<Integer, CellData<?>> cellDataMap = readSheet.getCellDataMap();
        Class<?> headClass = readSheet.getHeadClass();
        List<String> headNameList = readSheet.getHeadNameList();
        //根据HeadClass反射构建数据
        if (headClass != null) {
            List<Field> fieldList = FieldUtil.getSortedDeclaredFieldList(headClass);
            List<Converter> fieldConverterList = FieldUtil.getSortedDeclaredFieldConverterList(fieldList);
            List<String> fieldNameList = FieldUtil.getSortedDeclaredFieldNameList(fieldList);
            Map<String, Object> valueMap = new HashMap<>();
            try {
                resultObject = headClass.newInstance();
            } catch (Exception e) {
                throw new ExcelConvertException(readSheet.getRowIndex(), 0, null, "Can not instance class: " + headClass.getName());
            }
            for (Map.Entry<Integer, CellData<?>> entry : cellDataMap.entrySet()) {
                Integer index = entry.getKey();
                Converter<?> converter = fieldConverterList.get(index);
                CellData cellData = entry.getValue();
                Object value = null;
                try {
                    if (converter == null || converter instanceof DefaultConverter) {
                        Field field = fieldList.get(index);
                        value = ConverterUtil.convertToJavaObject(cellData, field);
                    } else {
                        value = converter.convertToJavaObject(cellData);
                    }
                } catch (Exception e) {
                    throw new ExcelConvertException(cellData.getRowIndex(), cellData.getColumnIndex(), cellData, "Can not instance class: " + headClass.getName());
                }
                valueMap.put(fieldNameList.get(index), value);
            }
            BeanMap.create(resultObject).putAll(valueMap);
        }
        //根据HeadFieldList构建Map数据
        else if (headNameList != null) {
            Map<String, Object> valueMap = new HashMap<>();
            for (Map.Entry<Integer, CellData<?>> entry : cellDataMap.entrySet()) {
                Integer index = entry.getKey();
                CellData<?> cellData = entry.getValue();
                valueMap.put(headNameList.get(index), cellData.getValue());
            }
            resultObject = valueMap;
        }
        //直接构建列索引-数据值 Map
        else {
            Map<Integer, Object> valueMap = new HashMap<>();
            for (Map.Entry<Integer, CellData<?>> entry : cellDataMap.entrySet()) {
                Integer index = entry.getKey();
                CellData<?> cellData = entry.getValue();
                valueMap.put(index, cellData.getValue());
            }
            resultObject = valueMap;
        }
        return resultObject;
    }

}
